package com.onlyforfun.exchange.chart;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.achartengine.ChartFactory;
import org.achartengine.GraphicalView;
import org.achartengine.chart.PointStyle;
import org.achartengine.model.TimeSeries;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;
import org.achartengine.tools.PanListener;

import android.graphics.Color;
import android.graphics.Paint.Align;
import android.os.AsyncTask;

import com.actionbarsherlock.app.SherlockActivity;
import com.onlyforfun.exchange.R;
import com.onlyforfun.exchange.dao.ExchangeDao;
import com.onlyforfun.exchange.domain.TimePrice;

public class HistoryPriceChart implements PanListener {

	private GraphicalView gv;
	
	private XYMultipleSeriesRenderer renderer;
	
	private long xAxisMax;
	
	private long xAxisMin;
	
	private XYMultipleSeriesDataset dataset;
	
	private List<TimePrice> timeprices;
	
	private SherlockActivity context;
	
	private ExchangeDao exchangeDao;
	
	private String currencyId;
	public HistoryPriceChart(SherlockActivity context, String currencyId, List<TimePrice> timeprices, ExchangeDao exchangeDao) {
		this.currencyId = currencyId;
		this.timeprices = timeprices;
		this.context = context;
		this.exchangeDao = exchangeDao;
	}

	/**
	 * Executes the chart .
	 * 
	 * @param context
	 *            the context
	 * @param timeprices 
	 * @return the built intent
	 */
	public GraphicalView execute() {
		String[] titles = new String[] { context.getResources().getString(R.string.timeprice_spotpurchaseprice), 
				context.getResources().getString(R.string.timeprice_cashpurchaseprice),
				context.getResources().getString(R.string.timeprice_spotofferprice),  
				context.getResources().getString(R.string.timeprice_cashofferprice)};
		List<Date[]> x = new ArrayList<Date[]>();
		
		for (int i = 0; i < titles.length; i++) {
			List<Date> dates = new ArrayList<Date>();
			for (int j = 0; j < timeprices.size(); j++) {
				dates.add(timeprices.get(j).getPublicTime());
			}
			x.add(dates.toArray(new Date[]{}));
		}
		List<Double[]> values = new ArrayList<Double[]>();
		
		List<Double> spotpuchase = new ArrayList<Double>();
		List<Double> spotoffer = new ArrayList<Double>();
		List<Double> cashpuchase = new ArrayList<Double>();
		List<Double> cashoffer = new ArrayList<Double>();
		double min = Double.MAX_VALUE;
		double max = 0;
		for (int j = 0; j < timeprices.size(); j++) {
			spotpuchase.add(timeprices.get(j).getSpotPurchasePrice());
			cashpuchase.add(timeprices.get(j).getCashPurchasePrice());
			spotoffer.add(timeprices.get(j).getSpotOfferPrice());
			cashoffer.add(timeprices.get(j).getCashOfferPrice());
			
			if (timeprices.get(j).getSpotPurchasePrice() < min
					&& timeprices.get(j).getSpotPurchasePrice() != 0) {
				min = timeprices.get(j).getSpotPurchasePrice();
			}
			
			if (timeprices.get(j).getSpotOfferPrice() < min
					&& timeprices.get(j).getSpotOfferPrice() != 0) {
				min = timeprices.get(j).getSpotOfferPrice();
			}
			
			if (timeprices.get(j).getCashPurchasePrice() < min
					&& timeprices.get(j).getCashPurchasePrice() != 0) {
				min = timeprices.get(j).getCashPurchasePrice();
			}
			
			if (timeprices.get(j).getCashOfferPrice() < min
					&& timeprices.get(j).getCashOfferPrice() != 0) {
				min = timeprices.get(j).getCashOfferPrice();
			}
			
			if (timeprices.get(j).getSpotPurchasePrice() > max) {
				max = timeprices.get(j).getSpotPurchasePrice();
			}
			
			if (timeprices.get(j).getSpotOfferPrice() > max) {
				max = timeprices.get(j).getSpotOfferPrice();
			}
			
			if (timeprices.get(j).getCashPurchasePrice() > max) {
				max = timeprices.get(j).getCashPurchasePrice();
			}
			
			if (timeprices.get(j).getCashOfferPrice() > max) {
				max = timeprices.get(j).getCashOfferPrice();
			}
		}
		values.add(spotpuchase.toArray(new Double[]{}));
		values.add(cashpuchase.toArray(new Double[]{}));
		values.add(spotoffer.toArray(new Double[]{}));
		values.add(cashoffer.toArray(new Double[]{}));
		int[] colors = new int[] { Color.BLUE, Color.GREEN, Color.CYAN,
				Color.YELLOW };
		
		PointStyle[] styles = new PointStyle[] { PointStyle.CIRCLE,
				PointStyle.DIAMOND, PointStyle.TRIANGLE, PointStyle.SQUARE };
		renderer = buildRenderer(colors, styles);
		int length = renderer.getSeriesRendererCount();
		for (int i = 0; i < length; i++) {
			((XYSeriesRenderer) renderer.getSeriesRendererAt(i))
					.setFillPoints(true);
		}
		xAxisMin = timeprices.get(timeprices.size() - 1).getPublicTime().getTime();
		xAxisMax = timeprices.get(0).getPublicTime().getTime();
		
		setChartSettings(renderer,
				context.getResources().getString(R.string.timeprice_trend_graph),
				context.getResources().getString(R.string.timeprice_publishtime),
				timeprices.get(0).getName(),
				xAxisMin,
				xAxisMax,
				min * 0.99,
				max * 1.01,
				Color.LTGRAY,
				Color.LTGRAY);
		renderer.setYLabels(10);
		renderer.setShowGrid(true);
		renderer.setXLabelsAlign(Align.RIGHT);
		renderer.setYLabelsAlign(Align.RIGHT);
		renderer.setXLabels(10); 
		
		renderer.setZoomButtonsVisible(true);
		dataset = buildDataset(titles, x, values);
		gv = ChartFactory.getTimeChartView(context,
				dataset, renderer,
				"H:mm");
		gv.addPanListener(this);
//		downloadTaskManagerThread.execute();
		return gv;
	}

	/**
	 * Builds an TIME multiple dataset using the provided values.
	 * 
	 * @param titles
	 *            the series titles
	 * @param xValues
	 *            the values for the X axis
	 * @param yValues
	 *            the values for the Y axis
	 * @return the XY multiple dataset
	 */
	protected XYMultipleSeriesDataset buildDataset(String[] titles,
			List<Date[]> xValues, List<Double[]> yValues) {
		XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
		addTimeSeries(dataset, titles, xValues, yValues, 0);
		return dataset;
	}

	public void addTimeSeries(XYMultipleSeriesDataset dataset, String[] titles,
			List<Date[]> xValues, List<Double[]> yValues, int scale) {
		int length = titles.length;
		for (int i = 0; i < length; i++) {
			TimeSeries series = new TimeSeries(titles[i]);
			Date[] xV = xValues.get(i);
			Double[] yV = yValues.get(i);
			int seriesLength = xV.length;
			for (int k = 0; k < seriesLength; k++) {
				series.add(xV[k], yV[k]);
			}
			dataset.addSeries(series);
		}
	}

	/**
	 * Builds an XY multiple series renderer.
	 * 
	 * @param colors
	 *            the series rendering colors
	 * @param styles
	 *            the series point styles
	 * @return the XY multiple series renderers
	 */
	protected XYMultipleSeriesRenderer buildRenderer(int[] colors,
			PointStyle[] styles) {
		XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
		setRenderer(renderer, colors, styles);
		return renderer;
	}

	protected void setRenderer(XYMultipleSeriesRenderer renderer, int[] colors,
			PointStyle[] styles) {
		renderer.setAxisTitleTextSize(16);
		renderer.setChartTitleTextSize(20);
		renderer.setLabelsTextSize(15);
		renderer.setLegendTextSize(15);
		renderer.setPointSize(2f);
		renderer.setMargins(new int[] { 20, 30, 15, 20 });
		int length = colors.length;
		for (int i = 0; i < length; i++) {
			XYSeriesRenderer r = new XYSeriesRenderer();
			r.setColor(colors[i]);
			r.setPointStyle(styles[i]);
			renderer.addSeriesRenderer(r);
		}
	}

	/**
	 * Sets a few of the series renderer settings.
	 * 
	 * @param renderer
	 *            the renderer to set the properties to
	 * @param title
	 *            the chart title
	 * @param xTitle
	 *            the title for the X axis
	 * @param yTitle
	 *            the title for the Y axis
	 * @param xMin
	 *            the minimum value on the X axis
	 * @param xMax
	 *            the maximum value on the X axis
	 * @param yMin
	 *            the minimum value on the Y axis
	 * @param yMax
	 *            the maximum value on the Y axis
	 * @param axesColor
	 *            the axes color
	 * @param labelsColor
	 *            the labels color
	 */
	protected void setChartSettings(XYMultipleSeriesRenderer renderer,
			String title, String xTitle, String yTitle, double xMin,
			double xMax, double yMin, double yMax, int axesColor,
			int labelsColor) {
		renderer.setChartTitle(title);
		renderer.setXTitle(xTitle);
		renderer.setYTitle(yTitle);
		renderer.setXAxisMin(xMin);
		renderer.setXAxisMax(xMax);
		renderer.setYAxisMin(yMin);
		renderer.setYAxisMax(yMax);
		renderer.setAxesColor(axesColor);
		renderer.setLabelsColor(labelsColor);
	}
	
	@Override
	public void panApplied() {
		SimpleDateFormat dateFormat = new SimpleDateFormat("M月d日");
    	Date minDate = new Date();
    	Date maxDate = new Date();
    	minDate.setTime((long) renderer.getXAxisMin());
    	maxDate.setTime((long) renderer.getXAxisMax());
    	
    	String strMin = dateFormat.format(minDate);
    	String strMax = dateFormat.format(maxDate);
    	
    	if (strMax.equals(strMin)) {
    		renderer.setXTitle("发布时间(" + strMin + ")");
    	} else {
    		renderer.setXTitle("发布时间(" + strMin + "~" + strMax + ")");
    	}
    	
		if (timeprices.get(0).getPublicTime().getTime() < renderer.getXAxisMax()) {
			context.setProgressBarVisibility(true);
			DownloadTimePriceTask priceTask = new DownloadTimePriceTask();
			priceTask.execute();
//			downloadTaskManager.addDownloadTask(priceTask);
		}
		
		if (timeprices.get(timeprices.size() - 1).getPublicTime().getTime() > renderer.getXAxisMin()) {
			context.setProgressBarVisibility(true);
			DownloadTimePriceTask priceTask = new DownloadTimePriceTask();
			priceTask.execute();
//			downloadTaskManager.addDownloadTask(priceTask);
		}
		
	}
	
	private class DownloadTimePriceTask extends AsyncTask<Date, Void, List<TimePrice>> {
	    @Override
	    protected List<TimePrice> doInBackground(Date... args) {
	    	List<TimePrice> tprices = null;
			synchronized (timeprices) {
				if (timeprices.get(0).getPublicTime().getTime() < renderer
						.getXAxisMax()) {
					Date end = new Date();
					tprices = exchangeDao.findByCurrencyName(end, end,
							currencyId);
				}

				if (timeprices.get(timeprices.size() - 1).getPublicTime()
						.getTime() > renderer.getXAxisMin()) {
					Date start = new Date();
					Date end = new Date();
					end.setTime(timeprices.get(timeprices.size() - 1)
							.getPublicTime().getTime());
					start.setTime((long) renderer.getXAxisMin());
					end.setDate(end.getDate() - 1);
					tprices = exchangeDao.findByCurrencyName(start, end, currencyId);
				}

				if (tprices == null || tprices.size() == 0) {
					return tprices;
				}
				if (tprices.get(0).getPublicTime().getTime() < timeprices
						.get(timeprices.size() - 1).getPublicTime().getTime()) {
					timeprices.addAll(tprices);
				} else {
					List<TimePrice> tmprices = new ArrayList<TimePrice>();
					for (int i = tprices.size() - 1; i >= 0; i--) {
						TimePrice element = tprices.get(i);
						if (element.getPublicTime().getTime() > timeprices.get(0).getPublicTime().getTime()) {
							timeprices.add(0, element);
							tmprices.add(element);
						}
					}
					tprices = tmprices;
				}
			}
			return tprices;
	    }

	    @Override
	    protected void onPostExecute(List<TimePrice> tprices) {
	    	
	    	if (tprices == null || tprices.size() == 0) {
//		    	context.setProgressBarVisibility(false);
	    		return;
	    	}
	    	for (TimePrice timePrice : tprices) {
				dataset.getSeries()[0].add(timePrice.getPublicTime().getTime(), timePrice.getSpotPurchasePrice());
				dataset.getSeries()[1].add(timePrice.getPublicTime().getTime(), timePrice.getCashPurchasePrice());
				dataset.getSeries()[2].add(timePrice.getPublicTime().getTime(), timePrice.getSpotOfferPrice());
				dataset.getSeries()[3].add(timePrice.getPublicTime().getTime(), timePrice.getCashOfferPrice());
			}
	    	
	    	gv.repaint();
//	    	context.setProgressBarVisibility(false);
	    }
	  }

}
